home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- ** **
- ** Module: BoxPaint_texture.c **
- ** **
- ** **
- ** Purpose: Code for a editable texture. **
- ** **
- ** **
- ** **
- ** Copyright (C) 1996-1997 Apple Computer, Inc. All rights reserved. **
- ** **
- ** **
- *****************************************************************************/
-
- #include <QuickDraw.h>
- #include <QDOffscreen.h>
- #include <stdlib.h>
- #include <math.h>
- #include <assert.h>
-
- #include "QD3D.h"
- #include "QD3DGroup.h"
- #include "QD3DShader.h"
- #include "QD3DStorage.h"
-
- #include "BoxPaint_texture.h"
- #include "BoxPaint_utility.h"
-
- /******************************************************************************
- ** **
- ** Structures **
- ** **
- *****************************************************************************/
-
- struct _texture {
-
- TQ3StoragePixmap fStoragePixmap; /* The Pixmap */
-
- unsigned char *fBuffer; /* The Buffer */
- unsigned long fBufferSize;
- long resolution; /* the height and width of the
- texture in pixels */
-
- PicHandle thePict; /* where the current texture is */
-
- };
-
- /******************************************************************************
- ** **
- ** Macros **
- ** **
- *****************************************************************************/
-
- #define PIXEL_TYPE unsigned long
- #define BYTES_PER_PIXEL (sizeof(PIXEL_TYPE))
- #define BITS_PER_PIXEL (8 * BYTES_PER_PIXEL)
-
- #define kPixelSpacing 1.0
- #define kPixelSpacingSqr (kPixelSpacing*kPixelSpacing)
- #define kMinSpacing 0.001
-
- #define DEFAULT_TEXTURE_RESOLUTION 128
-
- /******************************************************************************
- ** **
- ** Internal Routines **
- ** **
- *****************************************************************************/
-
- /**************************************
- ** **
- ** GENERAL TEXTURE **
- ** **
- **************************************/
-
- static void Texture_Init(
- TextureHdl theTexture);
-
-
- static void Texture_SetPixel(
- TexturePtr theTexture,
- unsigned long column,
- unsigned long row,
- PIXEL_TYPE color);
-
- static void Texture_PaintLineRC(
- TexturePtr pTexture,
- unsigned long oldColumn,
- unsigned long oldRow,
- unsigned long newColumn,
- unsigned long newRow);
-
-
- /**************************************
- ** **
- ** Buffer Routines **
- ** **
- **************************************/
-
- static TQ3Status Texture_BufferNew(
- TextureHdl theTexture);
-
- static void Texture_BufferDispose(
- TextureHdl theTexture);
-
-
- /**************************************
- ** **
- ** Texture Routines **
- ** **
- **************************************/
-
- static TQ3Status Texture_PixmapNew(
- TextureHdl theTexture);
-
- static void Texture_PixmapInit(
- TextureHdl theTexture);
-
- static void Texture_PixmapDispose(
- TextureHdl theTexture);
-
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_New()
- *
- * Comments: Allocates and inititalizes memory
- *
- \*===========================================================================*/
-
- TextureHdl Texture_New()
- {
- TextureHdl theTexture = (TextureHdl)Utility_MemoryNew(sizeof(Texture));
-
- if (!theTexture) goto bail;
-
- Texture_Init(theTexture);
-
- if (Texture_BufferNew(theTexture) == kQ3Failure) goto bail;
-
- if (Texture_PixmapNew(theTexture) == kQ3Failure) goto bail;
-
- return theTexture;
-
- bail:
- Texture_Dispose(theTexture);
- return NULL;
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_Dispose()
- *
- * Comments: Deallocates memory
- *
- \*===========================================================================*/
-
- void Texture_Dispose(TextureHdl theTexture)
- {
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
-
- Texture_BufferDispose(theTexture);
- Texture_PixmapDispose(theTexture);
-
- if ( (**theTexture).thePict != NULL) {
- KillPicture((**theTexture).thePict); /* Get rid of the Pict */
- }
-
- DisposeHandle((char **)theTexture);
-
- }
-
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_SetResolution()
- *
- * Comments: Sets the resolution of the pixmap
- *
- \*===========================================================================*/
-
- TQ3Status Texture_SetResolution(TextureHdl theTexture, long newResolution)
- {
- TQ3Status status = kQ3Failure;
- long savedResolution;
- PicHandle savedPict;
-
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
-
- savedResolution = (**theTexture).resolution;
- savedPict = (**theTexture).thePict;
-
- /*
- ** Get rid of the current buffer
- */
- Texture_BufferDispose(theTexture);
-
- Texture_PixmapDispose(theTexture);
-
- /*
- ** Set the new resolution
- */
- (**theTexture).resolution = newResolution;
-
- /*
- ** Grab a new texture based on the new resolution
- */
- Texture_BufferNew(theTexture);
-
- Texture_PixmapNew(theTexture);
-
- /*
- ** Set the pict to NULL (remember that we saved it). We do this
- ** because SetPict deletes existing pictures in the Texture.
- */
- (**theTexture).thePict = NULL;
-
- if ((status = Texture_SetPict(theTexture, savedPict)) != kQ3Success)
- {
- (**theTexture).resolution = savedResolution;
- }
-
- bail:
- return status;
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_GetResolution()
- *
- * Comments:
- *
- \*===========================================================================*/
-
- long Texture_GetResolution(TextureHdl theTexture)
- {
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
-
- return (**theTexture).resolution;
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_SetPict()
- *
- * Comments: Converts a PICT to a Texture. The pixmap buffer allocated
- * for this is not disposed and is returned so it can be
- * altered during the painting process.
- *
- \*===========================================================================*/
-
- TQ3Status Texture_SetPict(
- TextureHdl theTexture,
- PicHandle hPict)
- {
- TQ3Status status;
- QDErr err;
- unsigned long *textureMap,
- *pictMap,
- pictMapAddr,
- pictRowBytes;
- register unsigned long row,
- col;
- unsigned long width,
- height;
- Rect rectGW;
- GWorldPtr pGWorld;
- PixMapHandle hPixMap;
- GDHandle oldGD;
- GWorldPtr oldGW;
-
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
-
- status = kQ3Failure;
- pGWorld = NULL;
-
- /*
- ** Check to make sure all the parameters are valid
- */
-
- if (theTexture == NULL || (**theTexture).fBuffer == NULL || *theTexture == NULL) {
- return status;
- }
-
-
- /*
- ** If there already is a Pict, get rid of it
- */
-
- if ((**theTexture).thePict != NULL)
- {
- DisposeHandle((char **)(**theTexture).thePict);
- (**theTexture).thePict = NULL;
- }
-
- /*
- ** save current port
- */
-
- GetGWorld(&oldGW, &oldGD);
-
- width = (unsigned long) (**theTexture).resolution;
- height = (unsigned long) (**theTexture).resolution;
-
- /*
- ** Create the GWorld
- */
-
- SetRect(&rectGW, 0, 0, (unsigned short) width, (unsigned short) height);
-
- err = NewGWorld(&pGWorld, BITS_PER_PIXEL, &rectGW, NULL, NULL, useTempMem);
- if (err != noErr) {
- return status;
- }
-
- hPixMap = GetGWorldPixMap(pGWorld);
- pictMapAddr = (unsigned long) GetPixBaseAddr (hPixMap);
- pictRowBytes = (unsigned long) (**hPixMap).rowBytes & 0x3fff;
-
- /*
- ** Draw the PICT into the GWorld
- */
- SetGWorld(pGWorld, NULL);
-
- LockPixels(hPixMap);
- EraseRect(&rectGW);
- if(hPict)
- DrawPicture(hPict, &rectGW);
-
- /*
- ** Copy the PICT into the texture
- */
-
- /* (unsigned char *) textureMap = (**theTexture).fBuffer; */
- textureMap = (unsigned long *) (**theTexture).fBuffer;
- for (row = 0L; row < height; row++) {
- pictMap = (unsigned long *) (pictMapAddr + (pictRowBytes * row));
- for (col = 0L; col < width; col++) {
- *textureMap++ = (*pictMap++ | 0xff000000L);
- }
- }
-
- /*
- ** Update the object
- */
-
- if (Q3MemoryStorage_SetBuffer(
- (**theTexture).fStoragePixmap.image,
- (**theTexture).fBuffer,
- (**theTexture).fBufferSize,
- (**theTexture).fBufferSize) == kQ3Failure)
- goto bail;
-
- (**theTexture).thePict = hPict;
-
- UnlockPixels(hPixMap);
-
- if (((**theTexture).fStoragePixmap).image == NULL) {
- goto bail;
- }
- status = kQ3Success;
-
- bail:
-
- SetGWorld(oldGW, oldGD);
-
- /*
- ** Free GWorld
- */
-
- DisposeGWorld(pGWorld);
-
- /*
- ** Don't dispose "buffer" so the texture can be updated the texture
- ** with Q3MemoryStorage_SetBuffer later
- */
-
- return status;
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_SetToGroup()
- *
- * Comments: Sets a Pixmap to texture a group. If the group is already
- * texturized, the texture is replaced.
- *
- \*===========================================================================*/
-
- TQ3Status Texture_SetToGroup(TextureHdl theTexture, TQ3GroupObject theGroup)
- {
- TQ3StoragePixmap textureImage;
- TQ3TextureObject textureObject;
- TQ3GroupPosition position;
- TQ3Object firstObject;
-
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
-
- textureImage = (**theTexture).fStoragePixmap;
- textureObject = Q3PixmapTexture_New(&textureImage);
-
- /*
- ** if we have a texture object
- */
- if( textureObject ) {
- if( Q3Object_IsType(theGroup, kQ3GroupTypeDisplay) == kQ3True) {
- Q3Group_GetFirstPosition(theGroup, &position);
-
- Q3Group_GetPositionObject(theGroup, position, &firstObject);
-
- if( Q3Object_IsType(firstObject, kQ3SurfaceShaderTypeTexture) == kQ3True) {
- TQ3TextureObject oldTextureObject;
- TQ3StoragePixmap oldTextureImage;
-
- Q3TextureShader_GetTexture(firstObject, &oldTextureObject);
- Q3PixmapTexture_GetPixmap(oldTextureObject, &oldTextureImage);
-
- Q3Object_Dispose(oldTextureObject);
- Q3TextureShader_SetTexture(firstObject, textureObject);
- Q3Object_Dispose(textureObject);
-
- /*
- ** this is assuming that no other object uses this texture
- ** any more
- */
- Q3Object_Dispose(oldTextureImage.image);
- } else {
- TQ3ShaderObject textureShader;
-
- textureShader = Q3TextureShader_New(textureObject);
- Q3Object_Dispose(textureObject);
- Q3Group_AddObjectBefore(theGroup, position, textureShader);
- Q3Object_Dispose(textureShader);
- }
-
- Q3Object_Dispose(firstObject);
- } else if( Q3Object_IsType(theGroup, kQ3DisplayGroupTypeOrdered) == kQ3True) {
- TQ3ShaderObject textureShader;
-
- Q3Group_GetFirstPositionOfType(
- theGroup,
- kQ3ShapeTypeShader, &position);
-
- if( position ) {
- Q3Group_GetPositionObject(theGroup, position, &firstObject);
-
- if( Q3Object_IsType(firstObject, kQ3SurfaceShaderTypeTexture) == kQ3True) {
- TQ3TextureObject oldTextureObject;
- TQ3StoragePixmap oldTextureImage;
-
- Q3TextureShader_GetTexture(firstObject, &oldTextureObject);
- Q3PixmapTexture_GetPixmap(oldTextureObject, &oldTextureImage);
-
- Q3Object_Dispose(oldTextureObject);
- Q3TextureShader_SetTexture(firstObject, textureObject);
- Q3Object_Dispose(textureObject);
- } else {
- textureShader = Q3TextureShader_New(textureObject);
- if( textureShader ) {
- Q3Object_Dispose(textureObject);
- Q3Group_SetPositionObject(theGroup, position, textureShader);
- Q3Object_Dispose(textureShader);
- } else {
- return(kQ3Failure);
- }
- }
- } else {
- textureShader = Q3TextureShader_New(textureObject);
- if( textureShader ) {
- Q3Object_Dispose(textureObject);
- Q3Group_AddObject(theGroup, textureShader);
- Q3Object_Dispose(textureShader);
- } else {
- return(kQ3Failure);
- }
- }
-
- }
- return(kQ3Success);
- } else {
- return(kQ3Failure);
- }
- bail:
- return kQ3Failure;
-
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_Update()
- *
- * Comments: Updates QD3D to use the new texture in our stored memory.
- *
- \*===========================================================================*/
-
- TQ3Status Texture_Update(TexturePtr theTexture)
- {
- assert(theTexture != NULL);
-
- return Q3MemoryStorage_SetBuffer(
- theTexture->fStoragePixmap.image,
- theTexture->fBuffer,
- theTexture->fBufferSize,
- theTexture->fBufferSize);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_PaintLineUV()
- *
- * Comments: Paints a line across a texture given UV coordinates
- *
- \*===========================================================================*/
-
- void Texture_PaintLineUV(
- TexturePtr theTexture,
- TQ3Param2D from,
- TQ3Param2D to)
- {
- long fromRow, fromColumn,
- toRow, toColumn;
-
- assert(theTexture != NULL);
-
- fromColumn = theTexture->fStoragePixmap.height * from.u;
- fromRow = theTexture->fStoragePixmap.width * (1.0 - from.v);
-
- toColumn = theTexture->fStoragePixmap.height * to.u;
- toRow = theTexture->fStoragePixmap.width * (1.0 - to.v);
-
- Texture_PaintLineRC(
- theTexture,
- fromColumn,
- fromRow,
- toColumn,
- toRow);
- }
-
-
- /**************************************
- ** **
- ** LOCAL, PRIVATE ROUTINES **
- ** **
- **************************************/
-
- /*===========================================================================*\
- *
- * Routine: Texture_Init()
- *
- * Comments: Initializer
- *
- \*===========================================================================*/
-
- static
- void Texture_Init(TextureHdl theTexture)
- {
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
-
- /*
- ** Init the buffer
- */
- (**theTexture).fBuffer = NULL;
- (**theTexture).fBufferSize = 0;
-
- /*
- ** DEFAULT_TEXTURE_RESOLUTION: the height and width of the pict
- */
- (**theTexture).resolution = DEFAULT_TEXTURE_RESOLUTION;
-
- /*
- ** Init the Pict
- */
- (**theTexture).thePict = NULL;
-
- /*
- ** Init the Pixmap
- */
- Texture_PixmapInit(theTexture);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_SetPixel()
- *
- * Comments: Sets the pixels in the texture.
- *
- \*===========================================================================*/
-
- static
- void Texture_SetPixel( TexturePtr pTexture,
- unsigned long column,
- unsigned long row,
- PIXEL_TYPE color)
- {
- unsigned long rowBytes;
- unsigned char *pPixel,
- *pBufferStart,
- *pBufferEnd;
-
- assert(pTexture != NULL);
-
- /*
- ** Compute pixel in pixmap corresponding to (column,row)
- */
-
- rowBytes = pTexture->fStoragePixmap.rowBytes;
- pPixel = pTexture->fBuffer + rowBytes * row + column * BYTES_PER_PIXEL;
-
-
- /*
- ** Use these to test if the poked pixel falls within the fBuffer
- */
-
- pBufferStart = pTexture->fBuffer;
- pBufferEnd = pTexture->fBuffer + pTexture->fBufferSize;
-
- /*
- ** set the pixel
- */
-
- if ((pPixel >= pBufferStart) && (pPixel < pBufferEnd)) {
- *((PIXEL_TYPE *) pPixel) = color;
- }
-
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_PaintLineRC()
- *
- * Comments: Paints a continuous line of pixels between (oldColumn,oldRow)
- * and (newColumn,newRow)
- *
- \*===========================================================================*/
-
- static
- void Texture_PaintLineRC(
- TexturePtr pTexture,
- unsigned long oldColumn,
- unsigned long oldRow,
- unsigned long newColumn,
- unsigned long newRow)
- {
- unsigned long column,
- row;
- TQ3Vector2D srcVector2D;
- float t,
- spacing,
- pixelDistSqr;
-
- assert(pTexture != NULL);
-
- srcVector2D.x = (long) newColumn - (long) oldColumn;
- srcVector2D.y = (long) newRow - (long) oldRow;
-
- if ((srcVector2D.x == 0.0) &&
- (srcVector2D.y == 0.0)) {
-
- Texture_SetPixel(pTexture, newColumn, newRow, 0xFF000000);
- return;
- }
-
- /*
- ** Find distance from old to new pixel
- */
-
- pixelDistSqr = (srcVector2D.x * srcVector2D.x) +
- (srcVector2D.y * srcVector2D.y);
-
- spacing = kPixelSpacingSqr / pixelDistSqr;
- if (spacing < kMinSpacing) {
- spacing = kMinSpacing;
- }
-
- for (t = 0.0; t <= 1.0; t += spacing) {
-
- column = oldColumn + t * srcVector2D.x;
- row = oldRow + t * srcVector2D.y;
-
- Texture_SetPixel( pTexture, column, row, 0xFF000000);
- }
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_BufferNew()
- *
- * Comments: Allocates memory
- *
- \*===========================================================================*/
-
- static
- TQ3Status Texture_BufferNew(TextureHdl theTexture)
- {
- TQ3Status status = kQ3Failure;
- long i,j;
-
- long width = (**theTexture).resolution, height = (**theTexture).resolution;
-
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
- assert((**theTexture).fBuffer == NULL);
-
- /*
- ** Allocate a block of memory for the texture
- */
- (**theTexture).fBufferSize = width * height * BYTES_PER_PIXEL;
- (**theTexture).fBuffer = (unsigned char *) malloc((**theTexture).fBufferSize);
-
- /*
- ** Initialize the texture to white. This could be seriously optimized.
- */
-
- HLock((Handle)theTexture);
- for(i = 0; i < width; i++)
- for(j = 0; j < height; j++)
- Texture_SetPixel(*theTexture, i, j, 0xFFFFFFFF);
- HUnlock((Handle)theTexture);
-
- if ((**theTexture).fBuffer == NULL)
- {
- SysBeep(1);
- status = kQ3Failure;
- goto bail;
- }
-
- status = kQ3Success;
- bail:
-
- return status;
-
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_BufferDispose()
- *
- * Comments: Deallocates memory
- *
- \*===========================================================================*/
-
- static
- void Texture_BufferDispose(TextureHdl theTexture)
- {
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
-
- if ((**theTexture).fBuffer != NULL)
- {
- free((**theTexture).fBuffer);
- (**theTexture).fBuffer = NULL;
- }
- (**theTexture).fBufferSize = 0;
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_PixmapNew()
- *
- * Comments: Allocates memory
- *
- \*===========================================================================*/
-
- static
- TQ3Status Texture_PixmapNew(TextureHdl theTexture)
- {
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
-
- Texture_PixmapInit(theTexture);
-
- ((**theTexture).fStoragePixmap).image = Q3MemoryStorage_NewBuffer(
- (**theTexture).fBuffer,
- (**theTexture).fBufferSize,
- (**theTexture).fBufferSize);
- return kQ3Success;
- }
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_PixmapInit()
- *
- * Comments: Initializes the PixMap
- *
- \*===========================================================================*/
-
- static
- void Texture_PixmapInit(TextureHdl theTexture)
- {
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
-
- (**theTexture).fStoragePixmap.image = NULL;
- (**theTexture).fStoragePixmap.width = (**theTexture).resolution;
- (**theTexture).fStoragePixmap.height = (**theTexture).resolution;
- (**theTexture).fStoragePixmap.pixelSize = BITS_PER_PIXEL;
- (**theTexture).fStoragePixmap.rowBytes = (**theTexture).fStoragePixmap.width * BYTES_PER_PIXEL;
- (**theTexture).fStoragePixmap.pixelType = kQ3PixelTypeRGB32;
- (**theTexture).fStoragePixmap.bitOrder = kQ3EndianBig;
- (**theTexture).fStoragePixmap.byteOrder = kQ3EndianBig;
-
- }
-
-
-
- /*===========================================================================*\
- *
- * Routine: Texture_DisposePixMap()
- *
- * Comments: Deallocates memory
- *
- \*===========================================================================*/
-
- static
- void Texture_PixmapDispose(TextureHdl theTexture)
- {
- assert(theTexture != NULL);
- assert(*theTexture != NULL);
-
- /*
- ** if there is an image dispose of the storage object
- */
- if ((**theTexture).fStoragePixmap.image != NULL)
- {
- Q3Object_Dispose((**theTexture).fStoragePixmap.image);
- (**theTexture).fStoragePixmap.image = NULL;
- }
-
-
- }
-
-
-